package zz.app.jmhviewer;

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;

import zz.app.jmhviewer.JMH.JMHKana;

/**
 * Created by zz on 2018/1/30 10:00.
 */

public class KashiView extends View implements ValueAnimator.AnimatorUpdateListener{

    private Paint paint;
    private ArrayList<KashiPart> parts;
    private ArrayList<JMHKana> kanas;
    private String kashi;
    private String translate;
    private float kashiSize;
    private int kashiColor;
    private int currentKashiColor;
    private int kanaColor;
    private float currentKashiSize;
    private int animeTime;
    private float translateSize;
    private int translateColor;

    private int[] partsLine;
    private String[] translateContent;
    private float[] kashiLineWidth;
    private float[] translateLineWidth;
    private float kanaSize;
    private int kashiColorReal;
    private float kashiSizeReal;
    private float kashiHeight;
    private float kanaHeight;
    private float translateHeight;
    private float translateSizeReal;
    private float kanaSizeReal;
    private int paddingLR;
    private float currentKanaSize;
    private float currentTranslateSize;
    private float kanasizeScale;
    private int translatelinecnt;
    private ValueAnimator inAnim,outAnim;
    private Handler handler;
    private int flag=0;
    private int lastflag=-1;
    public static final int FLAG_DEFAULT=0;
    public static final int FLAG_IN_ANIM=1;
    public static final int FLAG_OUT_ANIM=2;
    public static final int FLAG_IN_FORCE=3;
    public static final int FLAG_OUT_FORCE=4;
    private boolean orienchanged;
    private float fontSizeOrienScale=1;
    private float fontSizeScale=1;

    public void setFontSizeOrienScale(float fontSizeOrienScale) {
        this.fontSizeOrienScale = fontSizeOrienScale;
    }

    public void setFontSizeScale(float fontSizeScale) {
        this.fontSizeScale = fontSizeScale;
    }

    public KashiView(Context context) {
        super(context);
        init();
    }
    public KashiView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {
        paint=new Paint(Paint.ANTI_ALIAS_FLAG);
        parts=new ArrayList<>();
        kanas=new ArrayList<>();
        kashi= "";
        translate="";
        paddingLR=30;
        kanasizeScale=0.6f;
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        float maxscreenwidth = MeasureSpec.getSize(widthMeasureSpec);
        float maxshowwidth=maxscreenwidth-2*paddingLR;
        int linecnt = 0;
        float temp = 0;
        int kashilinecnt;

        for (int i = 0; i < parts.size(); i++) {
            paint.setTextSize(kashiSizeReal);
            KashiPart part=parts.get(i);
            String s=part.content;
            if(!s.equals("\n")) {
                float width = paint.measureText(s);
                part.kanjiwidth=width;
                float tempindent=0;
                if(part.type==WordType.Kanji) {
                    paint.setTextSize(kanaSizeReal);
                    float originkanawidth = paint.measureText(part.kana.content);
                    float wantindent = part.kanjiwidth / part.kana.content.length() - originkanawidth / part.kana.content.length();
                    if (wantindent < 0){
                        wantindent=0;
                        if(i>0){
                            KashiPart p=parts.get(i-1);
                            float kanawidth=p.kanawidth;
                            float kanjiwidth=p.kanjiwidth;
                            if(p.type==WordType.Kanji){
                                part.wordindent =(originkanawidth+kanawidth-kanjiwidth-width)/2;
                                tempindent=part.wordindent;
                            }else{
                                if(p.content.equals(" ")){
                                    paint.setTextSize(kashiSizeReal);
                                    part.wordindent =paint.measureText(p.content);
                                }else {
                                    part.wordindent = (originkanawidth + kanawidth - kanjiwidth - width) / 2;
                                }
                                if(part.wordindent<0)part.wordindent=0;
                                tempindent=part.wordindent;
                            }

                        }
                    }else{
                        part.kanaindent=wantindent;

                    }
                    part.kanawidth=originkanawidth+wantindent*(part.kana.content.length()-1);
                    width+=tempindent;
                }
                if (temp + width < maxshowwidth) {
                    partsLine[i] = linecnt;
                    temp += width;
                } else {
                    kashiLineWidth[linecnt] = temp;
                    linecnt++;
                    temp = 0;
                    partsLine[i] = linecnt;
                    temp += width;
                }
            }else{
                kashiLineWidth[linecnt]=temp;
                linecnt++;
                temp = 0;
            }
        }
        kashiLineWidth[linecnt]=temp;
        kashilinecnt=linecnt;
        linecnt=0;
        paint.setTextSize(translateSizeReal);
        String s=translate;
        int startindex=0;
        int endindex=0;
        while(endindex<translate.length()) {
            while (paint.measureText(s.substring(startindex, endindex)) < maxshowwidth) {
                endindex++;
                if(endindex>=translate.length())
                    break;
            }
            translateLineWidth[linecnt]=paint.measureText(s.substring(startindex, endindex));
            translateContent[linecnt++]=s.substring(startindex, endindex);
            startindex=endindex;
        }

        translatelinecnt = linecnt;
        float maxheight = (kashilinecnt + 1) * (kanaHeight + kashiHeight)+(translatelinecnt+1)* translateHeight;
        setMeasuredDimension((int) (maxshowwidth+2*paddingLR), (int) maxheight);

    }

    public void setFlag(int flag) {
        this.flag = flag;
    }

    public int getFlag() {
        return flag;
    }

    public void update(){
        if(lastflag!=flag) {
            switch (flag) {
                case FLAG_IN_ANIM:
                    beginInAnim();
                    KashiScrollView view=(KashiScrollView)(getParent().getParent());
                    if (view.getAutoScroll()) {
                        view.scrollToAnim(view.getLeft(), getTop() +getHeight()/2 - view.getHeight() / 2, animeTime);
                    }
                    break;
                case FLAG_IN_FORCE:
                    if (inAnim != null && inAnim.isRunning()) inAnim.cancel();
                    beginIn();
                    break;
                case FLAG_OUT_ANIM:
                    beginOutAnim();
                    break;
                case FLAG_OUT_FORCE:
                case FLAG_DEFAULT:
                    if (outAnim != null && outAnim.isRunning()) outAnim.cancel();
                    beginOut();
                    break;
                default:
                    break;
            }
        }
        lastflag=flag;
        if(orienchanged){
            KashiScrollView view=(KashiScrollView)(getParent().getParent());
            if (view.getAutoScroll()) {
                view.scrollToAnim(view.getLeft(), getTop() +getHeight()/2 - view.getHeight() / 2, animeTime);
            }
            orienchanged=false;
        }

    }

    public void fresh(){
        calculate();
        requestLayout();
        invalidate();
    }

    private void calculate() {
        parts.clear();
        int length = kashi.length();
        int m=0;
        for (int i = 0; i < length; i++) {
            if (isKanasContain(i)) {
                KashiPart part = new KashiPart();
                JMHKana kana = getKanaByPos(i);
                if (kana != null) {
                    part.content = kashi.substring(kana.start, kana.end);
                    part.type = WordType.Kanji;
                    part.kana=kana;
                    parts.add(part);
                    i = kana.end-1;
                }
            } else {
                if (isEnglishChar(kashi, i)) {
                    int j = i;
                    for (; j < length; j++) {
                        if (!isEnglishChar(kashi, j)) break;
                    }
                    if (j > i) {
                        KashiPart part = new KashiPart();
                        part.content = kashi.substring(i, j);
                        part.type = WordType.English;
                        parts.add(part);
                        i = j-1;
                    }
                }else{
                    KashiPart part = new KashiPart();
                    part.type = WordType.None;
                    part.content = kashi.substring(i, i+1);
                    parts.add(part);
                }
            }
        }
        partsLine = new int[parts.size()];
        translateContent=new String[10];
        kashiLineWidth =new float[10];
        translateLineWidth =new float[10];
        paint.setTextSize(kashiSizeReal);
        Paint.FontMetrics metrics = paint.getFontMetrics();
        kashiHeight = metrics.bottom - metrics.top;


        paint.setTextSize(kanaSizeReal);
        metrics = paint.getFontMetrics();
        kanaHeight = metrics.bottom - metrics.top;
        paint.setTextSize(translateSizeReal);
        metrics = paint.getFontMetrics();
        translateHeight = metrics.bottom - metrics.top;

    }

    private boolean isEnglishChar(String kashi, int i) {
        char c=kashi.charAt(i);
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
    }


    private boolean isKanasContain(int i) {
        for(JMHKana kana:kanas){
            if(i>=kana.start&&i<kana.end)
                return true;
        }
        return false;
    }
    private JMHKana getKanaByPos(int i) {
        for(JMHKana kana:kanas){
            if(i>=kana.start&&i<kana.end)
                return kana;
        }
        return null;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width=canvas.getWidth();
        float startx=0;
        float starty=0;
        Paint.FontMetrics metrics;
        //1.DrawKashi
        paint.setColor(kashiColorReal);
        paint.setTextSize(kashiSizeReal);
        int currentline=-1;
        metrics=paint.getFontMetrics();
        for(int i=0;i<parts.size();i++) {
            KashiPart part = parts.get(i);
            if (currentline == partsLine[i]) {
                startx += paint.measureText(parts.get(i - 1).content) + parts.get(i).wordindent;
            } else {
                currentline = partsLine[i];
                startx = (width - kashiLineWidth[currentline]) / 2;
                starty = currentline * (kanaHeight + kashiHeight) + kanaHeight - metrics.top ;
            }
            String s = parts.get(i).content;
            canvas.drawText(s, startx, starty, paint);
            parts.get(i).startPos = startx;

        }
        int kashilinecnt=currentline;
        //2.DrawKana
        paint.setColor(kanaColor);
        paint.setTextSize(kanaSizeReal);
        metrics=paint.getFontMetrics();
        for(int i=0;i<parts.size();i++){
            KashiPart part=parts.get(i);
            if(part.type == WordType.Kanji){
                float originkanawidth=paint.measureText(part.kana.content);
                float wantindent=part.kanjiwidth /part.kana.content.length()-originkanawidth/part.kana.content.length();
                if(wantindent<0)wantindent=0;
                startx=(part.kanjiwidth -(wantindent*(part.kana.content.length()-1)+originkanawidth))/2+part.startPos;
                starty=partsLine[i]*(kanaHeight+kashiHeight)-metrics.top;
                for(int j=0;j<part.kana.content.length();j++){
                    String s=String.format("%c",part.kana.content.charAt(j));
                    canvas.drawText(s,startx,starty,paint);
                    startx+=paint.measureText(s)+wantindent;
                }
            }
        }
        //3.DrawTranslate
        paint.setColor(translateColor);
        paint.setTextSize(translateSizeReal);
        metrics=paint.getFontMetrics();
        for(int i=0;i<translatelinecnt;i++) {
            String s = translateContent[i];
            if(s!=null) {
                startx = (width - translateLineWidth[i]) / 2;
                starty = (kashilinecnt) * (kanaHeight + kashiHeight) + i * translateHeight + kanaHeight + kashiHeight - metrics.top ;
                canvas.drawText(s, startx, starty, paint);
            }
        }

    }

    public void setKashi(String s) {
        kashi=s;
    }
    public void setTranslate(String s) {
        translate=s;
    }
    public void setTranslateSize(float i){
        translateSizeReal=translateSize =i*fontSizeOrienScale*fontSizeScale;
    }
    public void setTranslateColor(int c){
        translateColor =c;
    }

    public void setKashiSize(float i) {
        kashiSizeReal=kashiSize =i*fontSizeOrienScale*fontSizeScale;
        kanaSizeReal=kanaSize = kashiSize *kanasizeScale;
    }

    public void setKashiColor(int c) {
        kashiColorReal=kashiColor =c;
    }

    public void setCurrentKashiColor(int c) {
        currentKashiColor =c;
    }

    public void setKanaColor(int c) {
        kanaColor =c;
    }

    public void setCurrentKashiSize(float i) {
        currentKashiSize =i*fontSizeOrienScale*fontSizeScale;
        currentKanaSize=currentKashiSize*kanasizeScale;
    }

    public void setAnimeTime(int i) {
        animeTime =i;
    }

    public void setPaddingLR(int p){
        paddingLR=p;
    }

    public void addKana(String c, int s, int e) {
        JMHKana kana=new JMHKana();
        kana.content=c;
        kana.start=s;
        kana.end=e;
        kanas.add(kana);
    }
    public void addKana(JMHKana kana) {
        kanas.add(kana);
    }
    private void setKashiColorReal(int c){
        kashiColorReal=c;
    }

    private void setKashiSizeReal(float size){
        kashiSizeReal=size;
    }

    private void setTranslateSizeReal(float size){
        translateSizeReal=size;
    }

    private void setKanaSizeReal(float size){
        kanaSizeReal=size;
    }

    public void beginInAnim(){
        inAnim=ValueAnimator.ofFloat(0,1);
        inAnim.addUpdateListener(this);
        inAnim.setDuration(animeTime);
        inAnim.start();

    }
    public void beginIn() {

        setKanaSizeReal(currentKanaSize);
        setKashiSizeReal(currentKashiSize);
        setKashiColorReal(currentKashiColor);
        setTranslateSizeReal(currentTranslateSize);
        fresh();
    }
    public void beginOut() {

        setKanaSizeReal(kanaSize);
        setKashiSizeReal(kashiSize);
        setKashiColorReal(kashiColor);
        setTranslateSizeReal(translateSize);
        fresh();
    }
    public void beginOutAnim(){
        outAnim=ValueAnimator.ofFloat(1,0);
        outAnim.addUpdateListener(this);
        outAnim.setDuration(animeTime);
        outAnim.start();
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float v=(float)animation.getAnimatedValue();
        setKanaSizeReal(kanaSize+(currentKanaSize-kanaSize)*v);
        setKashiSizeReal(kashiSize+(currentKashiSize-kashiSize)*v);
        setKashiColorReal(colorChangeByTime(kashiColor,currentKashiColor,v));
        setTranslateSizeReal(translateSize+(currentTranslateSize-translateSize)*v);
        fresh();

    }
    private int colorChangeByTime(int src,int des,float v){
        int srcr=Color.red(src);
        int srcg=Color.green(src);
        int srcb=Color.blue(src);
        int desr=Color.red(des);
        int desg=Color.green(des);
        int desb=Color.blue(des);
        int r=(int)(srcr+v*(desr-srcr));
        int g=(int)(srcg+v*(desg-srcg));
        int b=(int)(srcb+v*(desb-srcb));
        return Color.rgb(r,g,b);
    }


    public void setCurrentTranslateSize(float i) {
        currentTranslateSize=i*fontSizeOrienScale*fontSizeScale;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    public void orientationChanged() {
        orienchanged=true;
    }

    public void setHoriScale() {
        fontSizeOrienScale=1.4f;
    }

    public void setVertScale() {
        fontSizeOrienScale=1f;
    }

    class KashiPart{
        String content;
        JMHKana kana;
        WordType type;
        float startPos;
        float kanjiwidth;
        float kanawidth;
        float wordindent;
        float kanaindent;
    }
    private enum WordType {
        None,Kanji,English
    }

}

